package ru.papergames.battleserver.network;

import javolution.util.FastMap;
import org.apache.log4j.Logger;
import org.mmocore.network.MMOClient;
import org.mmocore.network.MMOConnection;
import ru.papergames.Config;
import ru.papergames.battleserver.model.AbstractPaperGameUser;
import ru.papergames.battleserver.model.UsersManager;
import ru.papergames.battleserver.model.WebServerClientHolder;
import ru.papergames.battleserver.network.serverpackets.flashuser.MessageFromWebServer;
import ru.papergames.battleserver.network.serverpackets.webserver.ForceReconnectRequest;
import ru.papergames.battleserver.network.serverpackets.webserver.WebServerServerPacket;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author: atroshanin
 * Date: 18.04.2010
 * Time: 16:46:03
 */
public class WebServerClient extends MMOClient<MMOConnection<WebServerClient>> {

    private static final Logger logger = Logger.getLogger(WebServerClient.class.getName());

    private boolean detached;

    private WebServerClientState state;

    private boolean plannedDisconnection;
    private boolean forceDisconnection;

    public enum WebServerClientState {
        CONNECTED, AUTHORIZED
    }

    public WebServerClient(final MMOConnection<WebServerClient> con) {
        super(con);
        state = WebServerClientState.CONNECTED;
        WebServerClientHolder.getInstance().setWebServerClientBeforeAuth(this);
    }

    public boolean isDetached() {
        return detached;
    }

    public void setDetached(boolean detached) {
        this.detached = detached;
    }

    public WebServerClientState getState() {
        return state;
    }

    public void setState(WebServerClientState state) {
        this.state = state;
    }

    public void sendPacket(WebServerServerPacket gsp) {
        if (detached) {
            return;
        }
        getConnection().sendPacket(gsp);
    }

    @Override
    public boolean decrypt(ByteBuffer buf, int size) {
        return true;
    }

    @Override
    public boolean encrypt(ByteBuffer buf, int size) {
        buf.position(buf.position() + size);
        return true;
    }

    public void setPlannedDisconnection(boolean plannedDisconnection) {
        this.plannedDisconnection = plannedDisconnection;
    }

    @Override
    protected void onDisconnection() {
        if (plannedDisconnection) {
            System.out.println("WebServerClient.onDisconnection: This is planned disconnection");
            return;
        }
        if (forceDisconnection) {
            System.out.println("WebServerClient.onDisconnection: Force disconnection. Trying to do force reconnect with tomcat");
            new SendForceReconnectTask().start();
        } else {
            closeFlashUsersConnections();
        }
/*
        // TODO: remove all battleorders for this battleserver!
*/
    }

    private void closeFlashUsersConnections() {

        if (!Config.LOG_OFF_USERS_WHEN_TOMCAT_RESTART) {
            logger.warn("===================================================================================================");
            logger.warn("[TOMCAT_RESTART]GOT notification about restarting tomcat. BUT we will skip it and NOT log off users");
            logger.warn("===================================================================================================");
            return;
        }

        //noinspection ThrowableInstanceNeverThrown
        logger.info("[TOMCAT_RESTART]Got notification about tomcat stop/restart.", new Throwable());
        detached = true;
        WebServerClientHolder.getInstance().setWebServerClient(null);

        FastMap<Long, AbstractPaperGameUser> map = UsersManager.getInstance().getAllPaperGameUsers();
        List<AbstractPaperGameUser> users = new ArrayList<AbstractPaperGameUser>(map.size());
        for (FastMap.Entry<Long, AbstractPaperGameUser> e = map.head(), end = map.tail(); (e = e.getNext()) != end;) {
            users.add(e.getValue());
        }
        UsersManager.getInstance().clearAllUsersAndRooms();
        byte [] forceLogout = "<res><messages><message>Force logout</message></messages><data><forceLogout>true</forceLogout></data></res>".getBytes();
        for (AbstractPaperGameUser usr : users) {
            usr.disconnect(new MessageFromWebServer(System.currentTimeMillis(), forceLogout, false));
        }
    }

    @Override
    protected void onForcedDisconnection() {
        forceDisconnection = true;
    }

    class SendForceReconnectTask extends Thread {
        public void run() {
            System.out.println("WebServerClient$SendForceReconnectTask.run start, " + new Date());
            sleepInternal(10000);
            System.out.println("WebServerClient$SendForceReconnectTask.run, sending ForceReconnectRequest packet, " + new Date());
            WebServerClientHolder.getInstance().sendForceReconnect(new ForceReconnectRequest());
            sleepInternal(5000);
            if (WebServerClientHolder.getInstance().isWebServerClientReady()) {
                System.out.println("WebServerClient$SendForceReconnectTask.run - planned disconnection, " + new Date());
                return;
            }
            closeFlashUsersConnections();
        }

        private void sleepInternal(long time) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                // skip it
            }
        }
    }
}
